package wowcatsim;

import wowcatsim.interfaces.CatStrategy;
import wowcatsim.interfaces.SimulatorView;
import wowcatsim.strategy.DoNothingStrategy;

public class Simulator {

    private SimulatorView view;
    private CatStrategy strategy = new DoNothingStrategy();
    private CatStatistics stats = new CatStatistics();
    private SimulatorSettings settings = new SimulatorSettings();
    private Equipment equip = new Equipment();
    private int runs = 1;
    private int threads = Runtime.getRuntime().availableProcessors();
    private int jobsSent = 0;
    private int jobsReceived = 0;
    private double dpsTotal = 0;
    private double dps2Total = 0;

    public Simulator(SimulatorView view) {
        this.view = view;
    }

    public void setStrategy(CatStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStats(CatStatistics stats) {
        this.stats = stats;
    }

    public void setSettings(SimulatorSettings settings) {
        this.settings = settings;
    }

    public void setRuns(int runs) {
        this.runs = runs;
    }

    public void setThreads(int threads) {
        this.threads = threads;
    }
    
    public void setEquipment(Equipment equip) {
        this.equip = equip;
    }

    synchronized public void start() throws InterruptedException {
        while (jobsReceived < runs) {
            while ((jobsSent < runs) && (jobsSent - jobsReceived < threads)) {
                SimulatorJob job = new SimulatorJob(this, jobsSent);
                job.setStrategy(strategy.clone());
                job.setStatistics(stats);
                job.setSettings(settings);
                job.setEquipment(equip);
                if (jobsSent == 1) {
                    job.setLog(true);
                }
                job.start();
                jobsSent++;
            }
            wait();
        }
        sendResults();
    }

    synchronized public void jobFinished(int jobId, double dps) {
        jobsReceived++;
        dpsTotal += dps;
        dps2Total += dps * dps;
        view.updateProgress(jobsReceived, runs);
        notify();
    }

    private void sendResults() {
        double mean = dpsTotal / runs;
        double stddev = Math.sqrt((dps2Total - runs * mean * mean) / (runs - 1));
        view.showResult(mean, stddev, stddev / Math.sqrt(runs));
    }

    public void log(String line) {
        view.log(line);
    }
}
